package com.phison.fenestrapro.dashboard.util;

import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletContext;

import org.apache.commons.io.IOUtils;

import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.ExceptionConverter;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import com.phison.fenestrapro.dashboard.FenestraProApplication;
import com.phison.fenestrapro.dashboard.data.Project;
import com.vaadin.service.ApplicationContext;
import com.vaadin.terminal.StreamResource.StreamSource;
import com.vaadin.terminal.gwt.server.WebApplicationContext;

/**
 *
 * 
 * @author Niall O'Hara
 *
 */
public class PdfHelper implements StreamSource, GlobalConstants {

	private static final long serialVersionUID = 1L;

	private final ByteArrayOutputStream os = new ByteArrayOutputStream();

	private static FenestraProApplication app;
	private static Project project;
	
	private static final Font HEADING =
			new Font(Font.HELVETICA, 18, Font.BOLD);
	
	private static final Font FOOTER =
			new Font(Font.HELVETICA, 11);

	private static final Font BOLD =
			new Font(Font.HELVETICA, 12, Font.BOLD);
	
	private static final Font BLUE =
			new Font(Font.HELVETICA, 12, Font.NORMAL, new Color(0, 178, 216));
	
	private static final Font GREYBOLD =
			new Font(Font.HELVETICA, 12, Font.BOLD, new Color(48, 48, 48));
	
	private static final Font BLUE_11 =
			new Font(Font.HELVETICA, 11, Font.NORMAL, new Color(0, 178, 216));
	
	private static final Font GREYBOLD_11 =
			new Font(Font.HELVETICA, 11, Font.BOLD, new Color(48, 48, 48));
	    
	/**
	 * @param theProject
	 * @param theApp
	 */
	public PdfHelper(Project theProject, FenestraProApplication theApp) {
		  
		Document document = new Document(PageSize.A4, 36, 36, 120, 36);
		app = theApp;
		project = theProject;
		
		
		try {
			PdfWriter writer = PdfWriter.getInstance(document, os);
			TableHeader eventHeader = new TableHeader();
			TableFooter eventFooter = new TableFooter();
			writer.setPageEvent(eventHeader);
			writer.setPageEvent(eventFooter);

			document.open();
			
			Paragraph sectionHeading = new Paragraph("1. Introduction", HEADING);
			sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(17);
			document.add(sectionHeading);
            generateIntro(document);
            document.newPage();

            sectionHeading = new Paragraph("2. Project Data", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateProjectData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("3. Building Data", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateBuildingData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("4. Building Geometry", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateBuildingGeometryData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("5. Thermal Performance", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateThermalPerformanceData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("6. Fa�ade Design", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateFacadeDesignData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("7. Shading", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			document.add(sectionHeading);
            generateShadingData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("8. Glazing", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			document.add(sectionHeading);
            generateGlazingData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("9. Typical Floor", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateTypicalFloorData(document);
            document.newPage();
            
            sectionHeading = new Paragraph("10. Design Summary", HEADING);
            sectionHeading.setIndentationLeft(10);
			sectionHeading.setSpacingBefore(0);
			sectionHeading.setSpacingAfter(21);
			document.add(sectionHeading);
            generateFacadeDesignSummaryData(document);
            document.newPage();
            
            for (int i = 1; i < 5; ++i) {
            	switch (i) {
					case 1: sectionHeading = new Paragraph("10." + i + " " + project.getFacadeOneOrientation() + " Fa�ade Summary", HEADING); break;
					case 2: sectionHeading = new Paragraph("10." + i + " " + project.getFacadeTwoOrientation() + " Fa�ade Summary", HEADING); break;
					case 3: sectionHeading = new Paragraph("10." + i + " " + project.getFacadeThreeOrientation() + " Fa�ade Summary", HEADING); break;
					case 4: sectionHeading = new Paragraph("10." + i + " " + project.getFacadeFourOrientation() + " Fa�ade Summary", HEADING); break;
				}
	            sectionHeading.setIndentationLeft(10);
				sectionHeading.setSpacingBefore(0);
				sectionHeading.setSpacingAfter(20);
				document.add(sectionHeading);
				generateFacadeSummaryData(document, i);
	            document.newPage();
            }
            
            document.addTitle(project.getProjName());
            document.addAuthor(app.getCurrentUserFirstName());
            document.addSubject(project.getProjDescription());
			
			document.addCreationDate();
			document.addCreator("FenestraPro Restricted Release (build 0." + app.getBuildNumber() + ")");

			document.close();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (document != null) {
				document.close();
			}
		}
	}

	private PdfPCell logo() {
		
		PdfPCell cell = new PdfPCell();
		try {
			Image logo = Image.getInstance(getBytesFromThemesFolder("img/fp.png"));
			logo.scaleToFit(250f, 100000f);
			cell.addElement(logo);
			cell.setBorder(Rectangle.NO_BORDER);
			cell.setPadding(5f);

		} catch (Exception e) {
			// e.printStackTrace();
			Chunk logoMarker = new Chunk("(LOGO SHOULD BE HERE)\n" + e);
			cell.setFixedHeight(36f);
			cell.addElement(logoMarker);

		}
		return cell;
	}
	
	public static void generateIntro(Document document) {
		
		Paragraph paragraph1 = new Paragraph(); 
		Paragraph paragraph2 = new Paragraph();
		Paragraph paragraph3 = new Paragraph();
		Paragraph paragraph4 = new Paragraph();
		
		paragraph1.setSpacingAfter(15);
		paragraph2.setSpacingAfter(15);
		paragraph3.setSpacingAfter(15);
		paragraph1.setIndentationLeft(10);
        paragraph1.setIndentationRight(10);
        paragraph2.setIndentationLeft(10);
        paragraph2.setIndentationRight(10);
        paragraph3.setIndentationLeft(10);
        paragraph3.setIndentationRight(10);
        paragraph4.setIndentationLeft(10);
        paragraph4.setIndentationRight(10);
        
		paragraph1.setAlignment(Element.ALIGN_JUSTIFIED);
		paragraph2.setAlignment(Element.ALIGN_JUSTIFIED);
		paragraph3.setAlignment(Element.ALIGN_JUSTIFIED);
		paragraph4.setAlignment(Element.ALIGN_JUSTIFIED);
        
        paragraph1.add(new Chunk("This report has been produced using "));
        paragraph1.add(new Chunk("Fenestra", GREYBOLD));
        paragraph1.add(new Chunk("Pro", BLUE));
        paragraph1.add(new Chunk(" Restricted Release, a software tool currently in development for architects to design environmentally efficient building fa�ades more cost effectively. It outlines inputs and outputs generated for information and design purposes only."));
        paragraph2.add(new Chunk("As "));
        paragraph2.add(new Chunk("Fenestra", GREYBOLD));
        paragraph2.add(new Chunk("Pro", BLUE)); 
        paragraph2.add(new Chunk(" is currently in development, all current users have been invited to use as early stage trial and demonstrative purposes, for response and opinion on functionality and usability, and to offer direction to develop the software from Prototype, to Beta, to full Version 1.0."));
        paragraph3.add(new Chunk("The outputs in this report are based on the inputs and specifications provided, and form a coherent record for performance specification at design stage."));
        paragraph4.add(new Chunk("Warning! Please note that this software is currently at trial and development stage. This report should therefore only be used for demonstration and information purposes.  The contents of this report should not be relied upon for any reason whatsoever.  We do not provide any warranty or representations of any kind in relation to the accuracy or completeness of the contents of this report, and exclude all liability and responsibility for any loss or damage you or any third party may suffer in reliance upon this report.  This report should be treated as strictly private and confidential and should not be disclosed, submitted or issued to any third party in any form."));
        
        try {
        	document.add(paragraph1);
        	document.add(paragraph2);
        	document.add(paragraph3);
        	document.add(paragraph4);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	public static void generateProjectData(Document document) {
		PdfPTable table = new PdfPTable(2);
		
		try {
			table.setWidths(new int[] { 40, 60 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			table.addCell(new Phrase("Name of Project", BOLD));
			table.addCell(project.getProjName());
			
			table.addCell(new Phrase("Project Number", BOLD));
			table.addCell(project.getProjNumber());
			
			table.addCell(new Phrase("Project Description", BOLD));
			table.addCell(project.getProjDescription());
			
			table.addCell(new Phrase("Report Created by", BOLD));
			table.addCell(app.getCurrentUserFirstName());
			
			table.addCell(new Phrase("Model Imported", BOLD));
			table.addCell("Not available in Restricted Release");
			
			DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			Date date = new Date();
			
			table.addCell(new Phrase("Date Generated", BOLD));
			table.addCell(dateFormat.format(date));
			
			//table.addCell(new Phrase("FenestraPro Version", BOLD));
			//table.addCell("Restricted Release (build 0." + app.getBuildNumber() + ")");
						
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateBuildingData(Document document) {
		PdfPTable table = new PdfPTable(2);

		try {
			table.setWidths(new int[] { 40, 60 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			table.addCell(new Phrase("Building Type", BOLD));
			table.addCell(project.getBuildingType());
			
			table.addCell(new Phrase("Fa�ade Type", BOLD));
			table.addCell(project.getFacadeType());
			
			table.addCell(new Phrase("Location", BOLD));
			table.addCell("Lat: " + project.getLatitude() + " / Long: " + project.getLongitude());
			
			table.addCell(new Phrase("Orientation", BOLD));
			table.addCell(project.getOrientation());
		
        	URL mapurl = new URL("http://maps.googleapis.com/maps/api/staticmap?center=" + project.getLatitude() + ","
        								+ project.getLongitude() + "&zoom=13&size=300x300&scale=2&sensor=false" +
        									"&markers=color:red%7C" + project.getLatitude() + ","
        								+ project.getLongitude() + "");
			Image map = Image.getInstance(getURLAsByteArray(mapurl));
			map.scaleToFit(250f, 250f);
			
			table.addCell(new Phrase("Map", BOLD));
			table.getDefaultCell().setPadding(0);
			table.addCell(map);
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateBuildingGeometryData(Document document) {
		PdfPTable table = new PdfPTable(2);

		try {
			table.setWidths(new int[] { 40, 60 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			table.addCell(new Phrase("Building Length", BOLD));
			table.addCell(project.getLength() + UNIT_m);
			
			table.addCell(new Phrase("Building Width", BOLD));
			table.addCell(project.getWidth() + UNIT_m);
			
			table.addCell(new Phrase("Building Height", BOLD));
			table.addCell(project.getOverallBuildingHeight()+ UNIT_m);
			
			table.addCell(new Phrase("Stories", BOLD));
			table.addCell("" + project.getStoreys());
			
			table.addCell(new Phrase("Floor to Floor Height", BOLD));
			table.addCell(project.getFloorToFloor() + UNIT_m);
			
			table.addCell(new Phrase("Floor to Ceiling Height", BOLD));
			table.addCell(project.getFloorToCeiling() + UNIT_m);
			
			table.addCell(new Phrase("Wall Thickness", BOLD));
			table.addCell(project.getWallThickness() + UNIT_m);
			
			table.addCell(new Phrase("Total Surface Area (At)", BOLD));
			table.addCell(project.getHeatLossElementsArea() + UNIT_m2);
			
			table.addCell(new Phrase("Total Wall Area", BOLD));
			table.addCell(project.getTotalFacadeArea() + UNIT_m2);
			
			table.addCell(new Phrase("Roof Area", BOLD));
			table.addCell(project.getRoofArea() + UNIT_m2);
			
			table.addCell(new Phrase("Footprint Area (Site Coverage)", BOLD));
			table.addCell(project.getGroundFloorArea() + UNIT_m2);
			
			table.addCell(new Phrase("Building Volume (V)", BOLD));
			table.addCell(project.getVolume() + UNIT_m3);
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateThermalPerformanceData(Document document) {
		PdfPTable table = new PdfPTable(3);

		try {
			table.setWidths(new int[] { 40, 30, 50 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			PdfPCell cell = new PdfPCell();
			cell.setBorder(PdfPCell.BOX);
			cell.setBorderColor(Color.LIGHT_GRAY);
			cell.setBorderWidth(0.5f);
			cell.setPaddingTop(0);
			cell.setPaddingBottom(7);
			cell.setPaddingLeft(5);
			cell.setPaddingRight(5);
			cell.setLeading(16, 0);
			
			Phrase cellContents = new Phrase("Average Elemental Thermal Performance", BOLD);
			cell.setPhrase(cellContents);
			cell.setRowspan(4);
			table.addCell(cell);
			
			table.addCell(new Phrase("Roof", BOLD));
			table.addCell(project.getuValueRoof() + UNIT_wm2k);
			
			table.addCell(new Phrase("Ground Floor", BOLD));
			table.addCell(project.getuValueGroundFloor() + UNIT_wm2k);
			
			table.addCell(new Phrase("Glazing", BOLD));
			table.addCell(project.getuValueGlazing() + UNIT_wm2k);
			
			table.addCell(new Phrase("Wall", BOLD));
			table.addCell(project.getuValueWalls() + UNIT_wm2k);
			
			cellContents = new Phrase("Maximum Average U-Value Total", BOLD);
			cell.setRowspan(1);
			cell.setColspan(2);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			table.addCell(project.getMaxAverageUvalueTotal() + UNIT_wm2k);
			
			cellContents = new Phrase("Maximum Average U-Value Fa�ade", BOLD);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			table.addCell(project.getMaxAverageUvalueFacade() + UNIT_wm2k);
			
			cellContents = new Phrase("Selected Fa�ade Performance", BOLD);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			table.addCell(project.getFacadePerformance() + UNIT_wm2k);
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateFacadeDesignData(Document document) {
		PdfPTable table = new PdfPTable(5);

		try {
			table.setWidths(new int[] { 50, 20, 20, 20, 20 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			PdfPCell cell = new PdfPCell();
			cell.setBorder(PdfPCell.BOX);
			cell.setBorderColor(Color.LIGHT_GRAY);
			cell.setBorderWidth(0.5f);
			cell.setPaddingTop(0);
			cell.setPaddingBottom(7);
			cell.setPaddingLeft(5);
			cell.setPaddingRight(5);
			cell.setLeading(16, 0);
			
			table.addCell(new Phrase("Total Fa�ade Surface Area", BOLD));
			Phrase cellContents = new Phrase(project.getTotalFacadeArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			table.addCell(cell);
			
			table.addCell(new Phrase("Total % Glazing", BOLD));
			cellContents = new Phrase(project.getMaxPercentageGlazing() + UNIT_perc);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell(new Phrase("Total Glazed Area", BOLD));
			cellContents = new Phrase(project.getTotalGlazedArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell(new Phrase("Total Wall Area", BOLD));
			cellContents = new Phrase(project.getTotalWallArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell("");
			table.addCell(new Phrase(project.getFacadeOneOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeTwoOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeThreeOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeFourOrientation(), BOLD));
			
			table.addCell(new Phrase("% Glazing", BOLD));
			table.addCell(project.getFacadeOneGlazedPercentage() + UNIT_perc);
			table.addCell(project.getFacadeTwoGlazedPercentage() + UNIT_perc); 
			table.addCell(project.getFacadeThreeGlazedPercentage() + UNIT_perc);
			table.addCell(project.getFacadeFourGlazedPercentage() + UNIT_perc);
			
			table.addCell(new Phrase("Glazed Area", BOLD));
			table.addCell(project.getFacadeOneGlazedArea() + UNIT_m2);
			table.addCell(project.getFacadeTwoGlazedArea() + UNIT_m2);
			table.addCell(project.getFacadeThreeGlazedArea() + UNIT_m2); 
			table.addCell(project.getFacadeFourGlazedArea() + UNIT_m2);
			
			table.addCell(new Phrase("Wall Area", BOLD));
			table.addCell(project.getFacadeOneWallArea() + UNIT_m2); 
			table.addCell(project.getFacadeTwoWallArea() + UNIT_m2);
			table.addCell(project.getFacadeThreeWallArea() + UNIT_m2);
			table.addCell(project.getFacadeFourWallArea() + UNIT_m2);

			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateShadingData(Document document) {
		PdfPTable table = new PdfPTable(5);

		try {
			table.setWidths(new int[] { 50, 20, 20, 20, 20 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			PdfPCell cell = new PdfPCell();
			cell.setBorder(PdfPCell.NO_BORDER);
			cell.setBorderColor(Color.LIGHT_GRAY);
			cell.setBorderWidth(0.5f);
			cell.setPaddingTop(0);
			cell.setPaddingBottom(7);
			cell.setPaddingLeft(5);
			cell.setPaddingRight(5);
			cell.setLeading(16, 0);
			table.addCell(cell);
				
			Phrase cellContents = new Phrase("Fa�ade Orientation", BOLD);
			cell.setBorder(PdfPCell.BOX);
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			cell.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			table.addCell(cell);
			
			table.addCell("");
			table.addCell(new Phrase(project.getFacadeOneOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeTwoOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeThreeOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeFourOrientation(), BOLD));
			
			table.addCell(new Phrase("Window Configuration Type", BOLD));
			table.addCell(project.getFacadeOneWindowConfig());
			table.addCell(project.getFacadeTwoWindowConfig());
			table.addCell(project.getFacadeThreeWindowConfig());
			table.addCell(project.getFacadeFourWindowConfig());
			
			table.addCell(new Phrase("Shading Type", BOLD));
			table.addCell(project.getFacadeOneWindowShadingType());
			table.addCell(project.getFacadeTwoWindowShadingType());
			table.addCell(project.getFacadeThreeWindowShadingType());
			table.addCell(project.getFacadeFourWindowShadingType());
			
			table.addCell(new Phrase("Shading Depth", BOLD));
			table.addCell(project.getFacadeOneWindowShadingDepth() + UNIT_m);
			table.addCell(project.getFacadeTwoWindowShadingDepth() + UNIT_m);
			table.addCell(project.getFacadeThreeWindowShadingDepth() + UNIT_m);
			table.addCell(project.getFacadeFourWindowShadingDepth() + UNIT_m);
			
			table.addCell(new Phrase("Louvre Angle", BOLD));
			table.addCell(project.getFacadeOneShadingAngle() + UNIT_deg);
			table.addCell(project.getFacadeTwoShadingAngle() + UNIT_deg);
			table.addCell(project.getFacadeThreeShadingAngle() + UNIT_deg);
			table.addCell(project.getFacadeFourShadingAngle() + UNIT_deg);
			
			table.addCell(new Phrase("Shading Factor", BOLD));
			table.addCell(project.getFacadeOneShadingFactor() + ""); 
			table.addCell(project.getFacadeTwoShadingFactor() + ""); 
			table.addCell(project.getFacadeThreeShadingFactor() + "");
			table.addCell(project.getFacadeFourShadingFactor() + "");
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateGlazingData(Document document) {
		PdfPTable table = new PdfPTable(6);

		try {
			table.setWidths(new int[] { 20, 30, 20, 20, 20, 20 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			PdfPCell cell = new PdfPCell();
			cell.setBorder(PdfPCell.NO_BORDER);
			cell.setBorderColor(Color.LIGHT_GRAY);
			cell.setBorderWidth(0.5f);
			cell.setPaddingTop(0);
			cell.setPaddingBottom(7);
			cell.setPaddingLeft(5);
			cell.setPaddingRight(5);
			cell.setLeading(16, 0);
			cell.setColspan(2);
			table.addCell(cell);
				
			Phrase cellContents = new Phrase("Fa�ade Orientation", BOLD);
			cell.setBorder(PdfPCell.BOX);
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			cell.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			table.addCell(cell);
			cell.setHorizontalAlignment(PdfPTable.ALIGN_LEFT);
			
			table.addCell(new Phrase("Floor", BOLD));
			table.addCell(new Phrase("Window Heights", BOLD));
			table.addCell(new Phrase(project.getFacadeOneOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeTwoOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeThreeOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeFourOrientation(), BOLD));
			
			for (int i = 0; i < project.getStoreys(); i++) {
				cellContents = new Phrase(floorNames[i], BOLD);
				cell.setPhrase(cellContents);
				cell.setColspan(1);
				cell.setRowspan(3);
				table.addCell(cell);
				
				table.addCell(new Phrase("Head", BOLD));
				table.addCell(project.getFacadeOneWindowHH()[i] + UNIT_m);
				table.addCell(project.getFacadeTwoWindowHH()[i] + UNIT_m);
				table.addCell(project.getFacadeThreeWindowHH()[i] + UNIT_m);
				table.addCell(project.getFacadeFourWindowHH()[i] + UNIT_m);
				
				table.addCell(new Phrase("Cill", BOLD));
				table.addCell(project.getFacadeOneWindowCH()[i] + UNIT_m);
				table.addCell(project.getFacadeTwoWindowCH()[i] + UNIT_m);
				table.addCell(project.getFacadeThreeWindowCH()[i] + UNIT_m);
				table.addCell(project.getFacadeFourWindowCH()[i] + UNIT_m);
				
				table.addCell(new Phrase("Reveal", BOLD));
				table.addCell(project.getFacadeOneWindowRV()[i] + UNIT_m);
				table.addCell(project.getFacadeTwoWindowRV()[i] + UNIT_m);
				table.addCell(project.getFacadeThreeWindowRV()[i] + UNIT_m);
				table.addCell(project.getFacadeFourWindowRV()[i] + UNIT_m);
			}
			
			cellContents = new Phrase("% Frame", BOLD);
			cell.setPhrase(cellContents);
			cell.setColspan(2);
			cell.setRowspan(1);
			table.addCell(cell);
			table.addCell(project.getFacadeOnePercentageFrame() + "%"); 
			table.addCell(project.getFacadeTwoPercentageFrame() + "%"); 
			table.addCell(project.getFacadeThreePercentageFrame() + "%"); 
			table.addCell(project.getFacadeFourPercentageFrame() + "%"); 

			cellContents = new Phrase("Diffuse Transmittance", BOLD);
			cell.setPhrase(cellContents);
			cell.setColspan(2);
			table.addCell(cell);
			cellContents = new Phrase(project.getDiffuseTransmittanceText() + "");
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			table.addCell(cell);
			
			cellContents = new Phrase("Maintenance Factor", BOLD);
			cell.setPhrase(cellContents);
			cell.setColspan(2);
			table.addCell(cell);
			cellContents = new Phrase(project.getMaintenanceFactorValue() + "");
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			table.addCell(cell);
			
			cellContents = new Phrase("Average Reflectance of Internal Surfaces", BOLD);
			cell.setPhrase(cellContents);
			cell.setColspan(2);
			table.addCell(cell);
			cellContents = new Phrase(project.getAverageReflectanceOfInteriorSurfacesText());
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			table.addCell(cell);
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateTypicalFloorData(Document document) {
		PdfPTable table = new PdfPTable(5);

		try {
			table.setWidths(new int[] { 50, 20, 20, 20, 20 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			PdfPCell cell = new PdfPCell();
			cell.setBorder(PdfPCell.BOX);
			cell.setBorderColor(Color.LIGHT_GRAY);
			cell.setBorderWidth(0.5f);
			cell.setPaddingTop(0);
			cell.setPaddingBottom(7);
			cell.setPaddingLeft(5);
			cell.setPaddingRight(5);
			cell.setLeading(16, 0);
				
			table.addCell(new Phrase("Internal Floor Area", BOLD));
			Phrase cellContents = new Phrase(project.getInternalFloorArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			table.addCell(cell);
			
			table.addCell(new Phrase("Internal Ceiling Area", BOLD));
			cellContents = new Phrase(project.getInternalCeilingArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell("");
			table.addCell(new Phrase(project.getFacadeOneOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeTwoOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeThreeOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeFourOrientation(), BOLD));
			
			table.addCell(new Phrase("Area Fa�ade/Floor", BOLD));
			table.addCell(project.getFacadeOneTypicalFloorArea() + UNIT_m2);
			table.addCell(project.getFacadeTwoTypicalFloorArea() + UNIT_m2);
			table.addCell(project.getFacadeThreeTypicalFloorArea() + UNIT_m2);
			table.addCell(project.getFacadeFourTypicalFloorArea() + UNIT_m2);
			
			table.addCell(new Phrase("Glazed Area/Floor", BOLD));
			table.addCell(project.getFacadeOneTypicalFloorGlazedArea() + UNIT_m2);
			table.addCell(project.getFacadeTwoTypicalFloorGlazedArea() + UNIT_m2);
			table.addCell(project.getFacadeThreeTypicalFloorGlazedArea() + UNIT_m2);
			table.addCell(project.getFacadeFourTypicalFloorGlazedArea() + UNIT_m2);
			
			table.addCell(new Phrase("Extent of Perimeter Zone", BOLD));
			cellContents = new Phrase(project.getExtentOfPerimeterZone() + UNIT_m2);
			cell.setPhrase(cellContents);
			table.addCell(cell);;
			
			table.addCell("");
			table.addCell(new Phrase(project.getFacadeOneOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeTwoOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeThreeOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeFourOrientation(), BOLD));
			
			table.addCell(new Phrase("Area Perimeter Zones", BOLD));
			table.addCell(project.getFacadeOneTypicalFloorPerimeterZoneArea() + UNIT_m2);
			table.addCell(project.getFacadeTwoTypicalFloorPerimeterZoneArea() + UNIT_m2);
			table.addCell(project.getFacadeThreeTypicalFloorPerimeterZoneArea() + UNIT_m2);
			table.addCell(project.getFacadeFourTypicalFloorPerimeterZoneArea() + UNIT_m2);
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void generateFacadeDesignSummaryData(Document document) {
		PdfPTable table = new PdfPTable(5);

		try {
			table.setWidths(new int[] { 50, 20, 20, 20, 20 });

			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			PdfPCell cell = new PdfPCell();
			cell.setBorder(PdfPCell.BOX);
			cell.setBorderColor(Color.LIGHT_GRAY);
			cell.setBorderWidth(0.5f);
			cell.setPaddingTop(0);
			cell.setPaddingBottom(7);
			cell.setPaddingLeft(5);
			cell.setPaddingRight(5);
			cell.setLeading(16, 0);
				
			table.addCell(new Phrase("Total Surface Area", BOLD));
			Phrase cellContents = new Phrase(project.getTotalFacadeArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			cell.setColspan(4);
			table.addCell(cell);
			
			table.addCell(new Phrase("Total % Glazing", BOLD));
			cellContents = new Phrase(project.getMaxPercentageGlazing() + UNIT_perc);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell(new Phrase("Total Glazed Area", BOLD));
			cellContents = new Phrase(project.getTotalGlazedArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell(new Phrase("Total Wall Area", BOLD));
			cellContents = new Phrase(project.getTotalWallArea() + UNIT_m2);
			cell.setPhrase(cellContents);
			table.addCell(cell);
			
			table.addCell("");
			table.addCell(new Phrase(project.getFacadeOneOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeTwoOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeThreeOrientation(), BOLD));
			table.addCell(new Phrase(project.getFacadeFourOrientation(), BOLD));
			
			table.addCell(new Phrase("Glazing Distribution", BOLD));
			table.addCell(project.getFacadeOneGlazedPercentage() + UNIT_perc);
			table.addCell(project.getFacadeTwoGlazedPercentage() + UNIT_perc);
			table.addCell(project.getFacadeThreeGlazedPercentage() + UNIT_perc);
			table.addCell(project.getFacadeFourGlazedPercentage() + UNIT_perc);
			
			table.addCell(new Phrase("Solar Load Per Unit Floor Area", BOLD));
			table.addCell(project.getFacadeOneAvgDailySolarLoadPerFloor() + UNIT_wm2);
			table.addCell(project.getFacadeTwoAvgDailySolarLoadPerFloor() + UNIT_wm2);
			table.addCell(project.getFacadeThreeAvgDailySolarLoadPerFloor() + UNIT_wm2);
			table.addCell(project.getFacadeFourAvgDailySolarLoadPerFloor() + UNIT_wm2);
			
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	

	public static void generateFacadeSummaryData(Document document, int facade) {
		PdfPTable table = new PdfPTable(2);
		
		try {
			table.setWidths(new int[] { 50, 50 });
			
			table.setSpacingAfter(30);
			table.setTotalWidth(500);
			table.setLockedWidth(true);
			table.getDefaultCell().setBorder(Rectangle.BOX);
			table.getDefaultCell().setBorderColor(Color.LIGHT_GRAY);
			table.getDefaultCell().setBorderWidth(0.5f);
			table.getDefaultCell().setPaddingTop(0);
			table.getDefaultCell().setPaddingBottom(7);
			table.getDefaultCell().setPaddingLeft(5);
			table.getDefaultCell().setPaddingRight(5);
			table.getDefaultCell().setLeading(16, 0);
			table.getDefaultCell().setVerticalAlignment(PdfPTable.ALIGN_TOP);
			table.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
			
			table.addCell(new Phrase("Surface Area", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneArea() + UNIT_m2); break;
				case 2: table.addCell(project.getFacadeTwoArea() + UNIT_m2); break;
				case 3: table.addCell(project.getFacadeThreeArea() + UNIT_m2); break;
				case 4: table.addCell(project.getFacadeFourArea() + UNIT_m2); break;
			}
			
			table.addCell(new Phrase("Wall Area", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneWallArea() + UNIT_m2); break;
				case 2: table.addCell(project.getFacadeTwoWallArea() + UNIT_m2); break;
				case 3: table.addCell(project.getFacadeThreeWallArea() + UNIT_m2); break;
				case 4: table.addCell(project.getFacadeFourWallArea() + UNIT_m2); break;
			}
			
			table.addCell(new Phrase("Glazed Area", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneGlazedArea() + UNIT_m2); break;
				case 2: table.addCell(project.getFacadeTwoGlazedArea() + UNIT_m2); break;
				case 3: table.addCell(project.getFacadeThreeGlazedArea() + UNIT_m2); break;
				case 4: table.addCell(project.getFacadeFourGlazedArea() + UNIT_m2); break;
			}
			
			table.addCell(new Phrase("% Glazed", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneGlazedPercentage() + UNIT_perc); break;
				case 2: table.addCell(project.getFacadeTwoGlazedPercentage() + UNIT_perc); break;
				case 3: table.addCell(project.getFacadeThreeGlazedPercentage() + UNIT_perc); break;
				case 4: table.addCell(project.getFacadeFourGlazedPercentage() + UNIT_perc); break;
			}
			
			table.addCell(new Phrase("% Frame", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOnePercentageFrame() + UNIT_perc); break;
				case 2: table.addCell(project.getFacadeTwoPercentageFrame() + UNIT_perc); break;
				case 3: table.addCell(project.getFacadeThreePercentageFrame() + UNIT_perc); break;
				case 4: table.addCell(project.getFacadeFourPercentageFrame() + UNIT_perc); break;
			}
			
			table.addCell(new Phrase("Shading Type", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneWindowShadingType()); break;
				case 2: table.addCell(project.getFacadeTwoWindowShadingType()); break;
				case 3: table.addCell(project.getFacadeThreeWindowShadingType()); break;
				case 4: table.addCell(project.getFacadeFourWindowShadingType()); break;
			}
			
			table.addCell(new Phrase("Shading Depth", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneWindowShadingDepth() + UNIT_m); break;
				case 2: table.addCell(project.getFacadeTwoWindowShadingDepth() + UNIT_m); break;
				case 3: table.addCell(project.getFacadeThreeWindowShadingDepth() + UNIT_m); break;
				case 4: table.addCell(project.getFacadeFourWindowShadingDepth() + UNIT_m); break;
			}
			
			table.addCell(new Phrase("Louvre Angle", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneShadingAngle() + UNIT_deg); break;
				case 2: table.addCell(project.getFacadeTwoShadingAngle() + UNIT_deg); break;
				case 3: table.addCell(project.getFacadeThreeShadingAngle() + UNIT_deg); break;
				case 4: table.addCell(project.getFacadeFourShadingAngle() + UNIT_deg); break;
			}
			
			table.addCell(new Phrase("Shading Factor", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneShadingFactor() + ""); break;
				case 2: table.addCell(project.getFacadeTwoShadingFactor() + ""); break;
				case 3: table.addCell(project.getFacadeThreeShadingFactor() + ""); break;
				case 4: table.addCell(project.getFacadeFourShadingFactor() + ""); break;
			}
			
			table.addCell(new Phrase("Solar Load Per Unit Floor Area", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneAvgDailySolarLoadPerFloor() + UNIT_wm2); break;
				case 2: table.addCell(project.getFacadeTwoAvgDailySolarLoadPerFloor() + UNIT_wm2); break;
				case 3: table.addCell(project.getFacadeThreeAvgDailySolarLoadPerFloor() + UNIT_wm2); break;
				case 4: table.addCell(project.getFacadeFourAvgDailySolarLoadPerFloor() + UNIT_wm2); break;
			}
			
			table.addCell(new Phrase("Diffuse Transmittance", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneDiffuseTransmittanceValue() + ""); break;
				case 2: table.addCell(project.getFacadeTwoDiffuseTransmittanceValue() + ""); break;
				case 3: table.addCell(project.getFacadeThreeDiffuseTransmittanceValue() + ""); break;
				case 4: table.addCell(project.getFacadeFourDiffuseTransmittanceValue() + ""); break;
			}
			
			table.addCell(new Phrase("Average Reflectance of Internal Surfaces", BOLD));
			switch (facade) {
				case 1: table.addCell(project.getFacadeOneAverageReflectanceOfInteriorSurfacesValue() + ""); break;
				case 2: table.addCell(project.getFacadeTwoAverageReflectanceOfInteriorSurfacesValue() + ""); break;
				case 3: table.addCell(project.getFacadeThreeAverageReflectanceOfInteriorSurfacesValue() + ""); break;
				case 4: table.addCell(project.getFacadeFourAverageReflectanceOfInteriorSurfacesValue() + ""); break;
			}
			
			for (int i = 0; i < project.getStoreys(); i++) {
				table.addCell(new Phrase(floorNames[i] + " Floor Design Daylight Factor", BOLD));
				switch (facade) {
					case 1: table.addCell(project.getFacadeOneAverageDesignDaylightFactor(i) + ""); break;
					case 2: table.addCell(project.getFacadeTwoAverageDesignDaylightFactor(i) + ""); break;
					case 3: table.addCell(project.getFacadeThreeAverageDesignDaylightFactor(i) + ""); break;
					case 4: table.addCell(project.getFacadeFourAverageDesignDaylightFactor(i) + ""); break;
				}
			}
						
			document.add(table);

		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Inner class to add a table as header.
	 */
	class TableHeader extends PdfPageEventHelper {
		/** The header text. */
		String header;
		/** The template with the total number of pages. */
		PdfTemplate total;

		/**
		 * Allows us to change the content of the header.
		 * 
		 * @param header
		 *            The new header String
		 */
		public void setHeader(String header) {
			this.header = header;
		}

		/**
		 * Creates the PdfTemplate that will hold the total number of pages.
		 * 
		 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter,
		 *      com.itextpdf.text.Document)
		 */
		public void onOpenDocument(PdfWriter writer, Document document) {
			total = writer.getDirectContent().createTemplate(30, 16);
		}

		/**
		 * Adds a header to every page
		 * 
		 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter,
		 *      com.itextpdf.text.Document)
		 */
		public void onEndPage(PdfWriter writer, Document document) {
			PdfPTable tableHeader = new PdfPTable(2);
			try {
				tableHeader.setWidths(new int[] { 24, 24 });
				tableHeader.setTotalWidth(527);
				tableHeader.setLockedWidth(true);
				
				PdfPCell cell = new PdfPCell();
				cell.setColspan(2);
				cell.setBorder(Rectangle.TOP);
				tableHeader.addCell(cell);
				
				tableHeader.getDefaultCell().setBorder(Rectangle.NO_BORDER);
				tableHeader.addCell(logo());
				tableHeader.addCell("");
				
				cell = new PdfPCell();
				cell.setColspan(2);
				cell.setBorder(Rectangle.BOTTOM);
				tableHeader.addCell(cell);
				
				tableHeader.writeSelectedRows(0, -1, 34, 803, writer.getDirectContent());
				
			} catch (DocumentException de) {
				throw new ExceptionConverter(de);
			}
		}

		/**
		 * Fills out the total number of pages before the document is closed.
		 * 
		 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter,
		 *      com.itextpdf.text.Document)
		 */
		public void onCloseDocument(PdfWriter writer, Document document) {
			ColumnText.showTextAligned(total, Element.ALIGN_LEFT, new Phrase(
					String.valueOf(writer.getPageNumber() - 1)), 2, 2, 0);
		}
	}

	/**
	 * Inner class to add a table as footer.
	 */
	class TableFooter extends PdfPageEventHelper {
		/** The header text. */
		String footer;
		/** The template with the total number of pages. */
		PdfTemplate total;

		/**
		 * Allows us to change the content of the footer.
		 * 
		 * @param footer
		 *            The new header String
		 */
		public void setHeader(String footer) {
			this.footer = footer;
		}

		/**
		 * Creates the PdfTemplate that will hold the total number of pages.
		 * 
		 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter,
		 *      com.itextpdf.text.Document)
		 */
		public void onOpenDocument(PdfWriter writer, Document document) {
			total = writer.getDirectContent().createTemplate(16, 16);
		}

		/**
		 * Adds a header to every page
		 * 
		 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter,
		 *      com.itextpdf.text.Document)
		 */
		public void onEndPage(PdfWriter writer, Document document) {
			PdfPTable tableFooter = new PdfPTable(3);
			try {
				
				tableFooter.setWidths(new int[] { 20, 40, 20});
				tableFooter.setTotalWidth(527);
				tableFooter.setLockedWidth(true);
				tableFooter.getDefaultCell().setBorder(Rectangle.NO_BORDER);
				
				PdfPCell footerCell = new PdfPCell();
				footerCell.setColspan(3);
				footerCell.setBorder(Rectangle.TOP);
				tableFooter.addCell(footerCell);
				
				tableFooter.getDefaultCell().setBorder(Rectangle.NO_BORDER);
				tableFooter.addCell(new Phrase("� Phison Ltd.", FOOTER));
				
				tableFooter.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
				
				Phrase footer = new Phrase();
				footer.add(new Chunk("Fenestra", GREYBOLD_11));
				footer.add(new Chunk("Pro", BLUE_11));
				footer.add(new Chunk(" Restricted Release (build 0." + app.getBuildNumber() + ")",FOOTER));
				tableFooter.addCell(footer);
				
				tableFooter.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
				tableFooter.addCell(new Phrase(String.format("Page %d ", writer.getPageNumber()), FOOTER));
				
				//tableFooter.addCell(Image.getInstance(total));
				
				tableFooter.writeSelectedRows(0, -1, 34, 36, writer.getDirectContent());
				
			} catch (DocumentException de) {
				throw new ExceptionConverter(de);
			}
		}

		/**
		 * Fills out the total number of pages before the document is closed.
		 * 
		 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter,
		 *      com.itextpdf.text.Document)
		 */
		public void onCloseDocument(PdfWriter writer, Document document) {
			ColumnText.showTextAligned(total, Element.ALIGN_LEFT, new Phrase(
					String.valueOf(writer.getPageNumber() - 1)), 2, 4, 0);
		}
	}

	public static byte[] getURLAsByteArray(URL theURL) throws IOException {
		InputStream inputStream = theURL.openStream();
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];

		int n = 0;
		while (-1 != (n = inputStream.read(buffer))) {
			output.write(buffer, 0, n);
		}
		inputStream.close();

		return output.toByteArray();
	}

	private byte[] getBytesFromContextResource(String url) throws IOException {
		ApplicationContext context = app.getContext();
		if (context instanceof WebApplicationContext) {
			ServletContext ctx = ((WebApplicationContext) context)
					.getHttpSession().getServletContext();
			// System.out.println("CONTEXT RESOURCE URL: " + url +
			// "\nREAL PATH: " + ctx.getRealPath(url));
			InputStream stream = ctx.getResourceAsStream(url);
			if (stream != null)
				return IOUtils.toByteArray(stream);

		}
		return null;
	}

	private byte[] getBytesFromFolder(String folder, String url)
			throws IOException {
		String pathSep = (folder.endsWith("/") || folder.endsWith("\\")) ? ""
				: "/";
		String path = new StringBuffer(folder).append(pathSep).append(url)
				.toString();
		byte[] bytes = getBytesFromContextResource(path.toString());
		return bytes;

	}

	public byte[] getBytesFromThemesFolder(String theme, String url)
			throws IOException {
		String folder = "/VAADIN/themes/" + theme;
		return getBytesFromFolder(folder, url);

	}

	public byte[] getBytesFromThemesFolder(String url) throws IOException {
		return getBytesFromThemesFolder(app.getTheme(), url);

	}

	public byte[] getBytesFromWebInfFolder(String url) throws IOException {
		return getBytesFromFolder("/WEB-INF/", url);

	}
	
	@Override
	public InputStream getStream() {
		// Here we return the pdf contents as a byte-array
		return new ByteArrayInputStream(os.toByteArray());
	}
}